#ifndef __BLACKQUEUE_H__
#define __BLACKQUEUE_H__

#include <iostream>
#include <queue>
#include "Task.hpp"
#include <pthread.h>
#include "LockGuard.hpp"

using namespace std;

const size_t gDefault=5;

template<class T>
class BlackQueue
{
private:
    bool isFull()
    {
        return bq_.size()==capacity_;
    }

    bool isEmpty()
    {
        return bq_.size()==0;
    }

public:
    BlackQueue(const size_t capacity=gDefault)
        :capacity_(capacity)
    {
        pthread_mutex_init(&mtx_,nullptr);
        pthread_cond_init(&full_,nullptr);
        pthread_cond_init(&empty_,nullptr);
    }

    void push(const T& data)
    {
        // pthread_mutex_lock(&mtx_);
        // //条件变量判满，要是满了不挂起等待
        // while(isFull())
        // {
        //     pthread_cond_wait(&full_,&mtx_);//在full_条件变量上阻塞
        // }
        // //push
        // bq_.push(data);

        // //signal唤醒在unlock外还是内都无所谓
        // pthread_cond_signal(&empty_);//唤醒在条件变量empty_阻塞队列阻塞的第一个线程
        // pthread_mutex_unlock(&mtx_);

        LockGuard lg(&mtx_);
        //条件变量判满，要是满了不挂起等待
        while(isFull())
        {
            pthread_cond_wait(&full_,&mtx_);//在full_条件变量上阻塞
        }
        //push
        bq_.push(data);

        //signal唤醒在unlock外还是内都无所谓
        pthread_cond_signal(&empty_);//唤醒在条件变量empty_阻塞队列阻塞的第一个线程


    }

    void pop(T* out)
    {
        // pthread_mutex_lock(&mtx_);
        // while(isEmpty())
        // {
        //     pthread_cond_wait(&empty_,&mtx_);
        // }

        // //pop逻辑
        // *out=bq_.front();
        // bq_.pop();
        
        // pthread_cond_signal(&full_);
        // pthread_mutex_unlock(&mtx_);

        LockGuard lg(&mtx_);
        while(isEmpty())
        {
            pthread_cond_wait(&empty_,&mtx_);
        }

        //pop逻辑
        *out=bq_.front();
        bq_.pop();
        
        pthread_cond_signal(&full_);
    }

    ~BlackQueue()
    {
        pthread_mutex_destroy(&mtx_);
        pthread_cond_destroy(&full_);
        pthread_cond_destroy(&empty_);
    }

private:
    queue<T> bq_;//一个场所
    size_t capacity_;//标定BlackQueue空间大小
    pthread_mutex_t mtx_;
    pthread_cond_t full_;//判满条件变量
    pthread_cond_t empty_;//判空条件变量
};

#endif